<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
  <title>ChatGPT</title>

  <link rel="shortcut icon" href="icon.png" />

  <!-- <script src="https://cdn.bootcdn.net/ajax/libs/axios/1.3.2/axios.min.js"></script>
  <script src="https://cdn.bootcdn.net/ajax/libs/vue/3.2.47/vue.global.prod.js"></script>
  <link rel="stylesheet" type="text/css" href="https://cdn.bootcdn.net/ajax/libs/element-plus/2.2.30/index.css">
  <script src="https://cdn.bootcdn.net/ajax/libs/element-plus/2.2.30/index.full.min.js"></script> -->
  <script src="/cdn_libs/vue.global.prod.js"></script>
  <link href="/cdn_libs/index.css" rel="stylesheet" type="text/css" />


  <script src="/cdn_libs/axios.min.js"></script>
  <script src="/cdn_libs/index.full.js"></script>

  <style type="text/css">
    html,body,#app{
      height: 100%;
      margin:0;
    }

    .chat{
      background-color: #272a37;
      height: 100%;
      display: flex;
      flex-direction: column;
      justify-content: space-between;
    }
    .chat .head{
      text-align: center;
      padding: 20px;
      color: #fff;
    }

    .chat .body{
      background-color: #323644;
      overflow: auto;
      height:100%; 
    }
    .chat .body::-webkit-scrollbar {
      width: 5px;
    }
    .chat .body::-webkit-scrollbar-track {
      background: #e0e0e0;
      border-radius: 3px;
    }
    .chat .body::-webkit-scrollbar-thumb {
      background-color: #c2c2c2;
      border-radius: 3px;
    }
    .chat-msg{
      display: flex;
      padding:20px 10px 10px 10px;
    }
    .chat .body .assistant{
      justify-content:flex-start;
    }
    .chat .body .assistant .content{
      background-color: #d9d9d9;
    }
    .chat .body .user{
      justify-content:flex-end;
    }
    .chat .body .user .content{
      background-color: #1d90f5;
      color:#fff;
    }
    .chat-msg .content{
      white-space: pre-wrap;
      font-size: 14px;
      max-width: 80%;
      margin:0 10px;
      padding:10px;
      border-radius: 8px;
    }
    .el-loading-mask{
      border-radius: 8px;
    }

    .chat .footer{
      padding: 20px;
      display: flex;
      justify-content: space-between;
    }
  </style>
</head>

<body>
<div id="app">
  <div class="chat">
    <div class="head">
      <!-- ApiKey<el-input v-model="apikey" type="password" style="width: 50%;margin:0 10px;" placeholder="请输入ChatGPT的API密钥"></el-input>
      <el-button type="primary" @click="saveKey">保存到浏览器</el-button>
      <el-button type="primary" @click="delKey">删除保存的密钥</el-button> -->
    </div>
    <div id="chat-body" class="body">
      <div v-for="v in msg" class="chat-msg" :class="v.role">
        <el-avatar v-if="v.role=='assistant'" :size="30" src="icon.png"></el-avatar>
        <pre class="content">{{v.content}}</pre>
      </div>
      <!-- 思考中图标 -->
      <div v-show="!canSend" class="chat-msg assistant">
        <el-avatar :size="30" src="icon.png"></el-avatar>
        <pre class="content animate__animated animate__fadeInUp">{{tmpTxt}}</pre>
      </div>
    </div>
    <div class="footer">
      <el-input v-model="input" :disabled="!canSend" type="textarea" placeholder="请输入内容(超过2000字可能出错不返回)" @keypress="pressEnter" rows="5" ></el-input>
      <el-button type="primary" :disabled="!canSend" style="margin-left:20px;" @click="send">发送</el-button>
      <el-button type="primary" style="margin-left:20px;" @click="downloadTxt">保存</el-button>
    </div>
  </div>
</div>

<script type="text/javascript">
  var app=Vue.createApp({
    data(){
      return{
        // saveName:'chatgpt-apikey',
        // apikey:'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',
        msg:[],//所有对话
        input:'',//输入
        canSend:true,
        tmpTxt:'',//临时流数据
        id: null,
      }
    },
    computed:{

    },
    created(){
      // this.apikey=localStorage.getItem(this.saveName)
    },
    methods:{
      downloadTxt() {
        let element = document.createElement("a");
        let text ='';
        this.msg.forEach(element => {
          if(element.role=='user'){
            text+='\r\n你：'+element.content+'\r\n';
          }else if(element.role=='assistant'){
            text+='\r\nAI：'+element.content+'\r\n';
          }else if(element.role=='system'){
            text+='\r\n设定：'+element.content+'\r\n';
          }
        });
        let file = new Blob([text], { type: 'text/plain' });
        element.href = URL.createObjectURL(file);
        element.download = "download.txt";
        element.click();
      },
      //回车
      pressEnter(){
        if(event.keyCode == 13){
          event.preventDefault()//禁止默认换行
          this.send()
        }
      },
      //发送消息
      send(){
        //判断apikey
        // if(!this.apikey){
        //   this.$message.error('请输入ChatGPT的API密钥')
        //   return
        // }
        //判断发言
        if(!this.input){
          this.$message.error('请输入问题')
          return
        }

        //显示你的发言
        this.msg.push({role:'user',content:this.input})

        //禁止输入和发送
        this.canSend=false

        //滚动lhtask
        let chatBody=document.getElementById('chat-body')
        setTimeout(()=>{chatBody.scrollTop = chatBody.scrollHeight},100)

        let data = {'msg': this.input, 'id':this.id}

        //清空输入框
        this.input=''

        axios.post('https://liaocat.msns.cn:8011/user', data, {
            headers: {
              'Content-Type': 'application/json'
            }
          }).then(response => {
              this.id = response.data.id
              if (window.EventSource) {
                let ainFlag = true
                let waitFlag = true
                const source = new EventSource('https://liaocat.msns.cn:8011/user/sse/data?id='+this.id);
                let reconnectTimeout;

                source.addEventListener('open', () => {
                  console.log('Connected');
                  clearTimeout(reconnectTimeout);
                }, false);

                let ain = setInterval(() => {
                  if(waitFlag){
                  if(ainFlag){
                    this.tmpTxt = this.tmpTxt.replace('______','')
                    this.tmpTxt+="____"
                    ainFlag = false
                  }else{
                    this.tmpTxt = this.tmpTxt.replace('____','')
                    this.tmpTxt+="______"
                    ainFlag = true
                  }
                  }
                }, 100);

                source.addEventListener('close', e => {
                this.msg.push({role:'assistant',content:this.tmpTxt})
                  source.close();
                  waitFlag = false
                  clearInterval(ain)
                  this.tmpTxt = this.tmpTxt.replace('______','')
                  this.tmpTxt = this.tmpTxt.replace('____','')
                  this.canSend=true
                  this.tmpTxt=''
                  //滚动到底部
                  chatBody.scrollTop = chatBody.scrollHeight
                }, false);

                source.addEventListener('pause', e => {
                  source.close();
                  const reconnectTime = +e.data;
                  const currentTime = +new Date();
                  reconnectTimeout = setTimeout(() => {
                  }, reconnectTime - currentTime);
                }, false);

                // 服务器发送信息到客户端时，如果没有 event 字段，默认会触发 message 事件
                source.addEventListener('message', e => {
                  waitFlag = false
                  console.log(`data: ${e.data}`);
                  this.tmpTxt = this.tmpTxt.replace('______','')
                  this.tmpTxt = this.tmpTxt.replace('____','')
                  this.tmpTxt += JSON.parse(e.data.replace(/'/g, '"')).msg
                  this.id = JSON.parse(e.data.replace(/'/g, '"')).id
                  waitFlag = true
                }, false);

                // 自定义 EventHandler，在收到 event 字段为 slide 的消息时触发
                source.addEventListener('slide', e => {
                  console.log(`data: ${e.data}`); // => data: 7
                }, false);

                // 连接异常时会触发 error 事件并自动重连
                source.addEventListener('error', e => {
                  if (e.target.readyState === EventSource.CLOSED) {
                    console.log('Disconnected');
                    waitFlag = false
                    clearInterval(ain)
                    this.tmpTxt = this.tmpTxt.replace('______','')
                    this.tmpTxt = this.tmpTxt.replace('____','')
                    this.canSend=true
                    this.tmpTxt=''
                    this.msg.push({role:'assistant',content:this.tmpTxt})
                    alert('Disconnected')
                  } else if (e.target.readyState === EventSource.CONNECTING) {
                    console.log('Connecting...');
                  }
                }, false);
              } else {
                console.error('Your browser doesn\'t support SSE');
                alsert('Your browser doesn\'t support SSE');
              }
            })
            .catch(error => {
              console.log(error);
            });


        // //处理流数据
        // let decoder = new TextDecoder()
        // let parseStream=(value)=>{
        //   let tmp=decoder.decode(value)
        //   let data=tmp.split('\n')
        //   for (let v of data) {
        //     if(!v)continue
        //     if(v=='data: [DONE]')break
        //     let json=JSON.parse(v.substr(6))
        //     let text=json.choices[0].delta.content??''
        //     if(text=='\n\n'&&this.tmpTxt=='')continue//去掉开头的换行
        //     if(text)this.tmpTxt+=text
        //   }
        // }

      //   //结束处理
      //   let fin=()=>{
      //     this.msg.push({role:'assistant',content:this.tmpTxt})
      //     this.canSend=true
      //     this.tmpTxt=''

      //     //消息长度控制在30
      //     let spli=this.msg.length-30
      //     if(spli>0)this.msg.splice(0,spli)

      //     //滚动到底部
      //     chatBody.scrollTop = chatBody.scrollHeight
      //   }

      //   fetch('https://api.liaocatcat.xyz/v1/chat/completions',{
      //     method:'POST',
      //     headers:{
      //       'Content-Type':'application/json',
      //       'Authorization': 'Bearer '+this.apikey
      //     },
      //     body:JSON.stringify({
      //       model: 'gpt-3.5-turbo',
      //       messages:this.msg,
      //       temperature: 0.6,
      //       stream: true,
      //     }),
      //   }).then(o=>{
      //     let reader = o.body.getReader()
      //     new ReadableStream({
      //       start(controller) {
      //         let push=()=>{
      //           reader.read().then(({ done, value }) => {
      //             if (done) {
      //               fin()//结束处理
      //               controller.close()
      //               return
      //             }

      //             parseStream(value)//处理数据

      //             controller.enqueue(value)
      //             push()
      //           })
      //         }
      //         push()
      //       },
      //     })
      //   }).catch(e=>{
      //     this.$alert(e.message)
      //   })
      }
      //保存密钥
      // saveKey(){
      //   localStorage.setItem(this.saveName, this.apikey)
      //   this.$message.success('已保存')
      // },
      //删除密钥
      // delKey(){
      //   localStorage.removeItem(this.saveName)
      //   this.apikey=''
      //   this.$message.success('成功删除缓存密钥')
      // }
    }
  })
  app.use(ElementPlus)
  app.mount("#app")
</script>
</body>
</html>